package mk

import (
	"bytes"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"fmt"
	"io/ioutil"
	"net/http"
	"new_for_deepseek_rabbitmq/config"
	redisProject "new_for_deepseek_rabbitmq/project/redis"
	"time"
)

const (
	LOGIN_URL = "/opservice/tenant/login"
)

// LoginRequest 登录请求结构体
type LoginRequest struct {
	Times    int    `json:"times"`
	Username string `json:"username"`
	Passwd   string `json:"passwd"`
}

// LoginResponse 登录响应结构体
type LoginResponse struct {
	Code int    `json:"code"`
	Flag int    `json:"flag"`
	Desc string `json:"desc"`
	Data string `json:"data"`
}

// Login 登录方法
func (m *Mk) Login() (string, error) {
	redisClient := redisProject.GetInstance().GetClient()
	token, err := redisClient.Get(redisProject.MkTokenKey).Result()
	if err != nil {
		if err != redisProject.Nil {
			// token不存在，需要重新登录获取
			return "", fmt.Errorf("获取token失败: %v", err)
		}
	}

	if token != "" {
		return token, nil
	}

	// 解析公钥
	block, _ := pem.Decode([]byte(config.DefaultConfig.Mk.RsaPublic))
	if block == nil {
		return "", fmt.Errorf("解析PEM格式公钥失败")
	}

	pubKey, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return "", fmt.Errorf("解析公钥失败: %v", err)
	}

	rsaPubKey, ok := pubKey.(*rsa.PublicKey)
	if !ok {
		return "", fmt.Errorf("无效的RSA公钥")
	}

	username := config.DefaultConfig.Mk.Username
	password := config.DefaultConfig.Mk.Password

	// 使用crypto/rand作为随机数生成器
	encryptedPass, err := rsa.EncryptPKCS1v15(rand.Reader, rsaPubKey, []byte(password))
	if err != nil {
		return "", fmt.Errorf("密码加密失败: %v", err)
	}

	// 登录时间
	loginTimes := config.DefaultConfig.Mk.LoginTime

	// 登录请求
	loginReq := LoginRequest{
		Times:    loginTimes,
		Username: username,
		Passwd:   "MKENC(" + base64.StdEncoding.EncodeToString(encryptedPass) + ")",
	}

	// 登录请求转json
	jsonData, err := json.Marshal(loginReq)
	if err != nil {
		return "", err
	}

	// 发送curl post json请求
	req, err := http.NewRequest("POST", config.DefaultConfig.Mk.Url+LOGIN_URL, bytes.NewBuffer(jsonData))
	if err != nil {
		return "", err
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("supplier", config.DefaultConfig.Mk.Supplier)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	// 读取响应体
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	// 解析响应体
	var loginResp LoginResponse
	if err := json.Unmarshal(body, &loginResp); err != nil {
		return "", err
	}

	// 判断登录是否成功
	if loginResp.Code != 0 {
		return "", fmt.Errorf("登录失败: %s", loginResp.Desc)
	}

	// 设置Redis过期时间比登录时间提前5分钟，避免token在使用时突然失效
	expiration := time.Duration(loginTimes-300) * time.Second
	if err := redisClient.Set(redisProject.MkTokenKey, loginResp.Data, expiration).Err(); err != nil {
		return "", fmt.Errorf("保存token到Redis失败: %v", err)
	}

	// 返回token
	return loginResp.Data, nil
}
